package com.fdb.efp.nls.service.util;

import com.fdb.basic.framework.core.util.HexadecimalUtil;
import com.fdb.basic.framework.core.util.StringUtil;
import com.fdb.efp.nls.service.domain.TxtFileLoadBean;
import org.apache.commons.lang3.StringEscapeUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

/**
 * 开发人员：【chenxuan】
 * 创建/修改日期：【2019/5/16】
 * 功能描述：从文本读取文件，绑定数据对指定对象，并返回对象List
 * @Param
 * @return
 **/
public class TxtFileLoadPlugin {
	private static Logger logger = LoggerFactory.getLogger(TxtFileLoadPlugin.class);
	// 文件路径
	private String fileUrl;
	/* 文件流(按缓冲区大小读取) */
	private BufferedReader br;
	/* 缓冲区大小(K) */
	private int loadBufferSize = 1024;
	/* 文件字段数据分隔符(注意在Java中有许多字符需要转义) */
	private String dataSplit = "";
	/* 文件编码格式 */
	private String fileCharset="UTF-8";
	/* 去除文档开头行数 */
	private int IsFirstline = 0;
	/* 文件总共记录数统计 */
	private int fileRecordCount;
	/* 每次结束条数 */
	private int endCount;
	/* 每次读取条数 */
	private int readCount;
	/* 每次0条 */
	int start = 0;
	/**继续读取，插件会在第二次读取时赋值为true，以获取上次打开的文件流*/
	public boolean isFirstRead= true;

	public TxtFileLoadPlugin(String fileUrl, String dataSplit, String fileCharset, int isFirstline, int readCount) {
		this.fileUrl = fileUrl;
		this.dataSplit = dataSplit;
		this.fileCharset = fileCharset;
		IsFirstline = isFirstline;
		this.readCount = readCount;
		this.endCount = readCount;
	}
	/**
	 * 开发人员：【chenxuan】
	 * 创建/修改日期：【2019/5/17】
	 * 修改描述：读取文件到指定文件中
	 * @Param [obj]
	 * @return java.util.List<com.fdb.efp.nls.service.domain.TxtFileLoadBean>
	 **/
	public List<TxtFileLoadBean> run(TxtFileLoadBean obj ) throws Exception {
		// 加载文件

		// 取得连接
		double before = System.currentTimeMillis();
		List<TxtFileLoadBean> list = new ArrayList<>(endCount-start+1);
		try {
			if(isFirstRead){
				loadTxt();
				// 构建文件流
				br = new BufferedReader(new InputStreamReader(new FileInputStream(
						fileUrl), fileCharset), loadBufferSize * 1024);
				// 初始化分隔符
				dataSplit = StringEscapeUtils.escapeJava(dataSplit);
			}
			if (dataSplit.trim().equals("|")) {
				dataSplit = "\\" + dataSplit;
			}else if(dataSplit.trim().equals("||")) {
				dataSplit = "\\|\\\\|";
			}
			dataSplit = HexadecimalUtil.dealHexadecimal(dataSplit);
			list = fetchDataToObject(start, endCount,obj);
			start = endCount + 1;
			endCount = endCount + readCount;
			//显示总共多少条记录,以及成功导入了多少条
			logger.info("已读取文件总记录数:" + fileRecordCount);
			double after = System.currentTimeMillis();
			logger.info("本次读取耗时[" + (after - before) / 1000 + "]秒");
		}
		catch(Exception e){
			obj.isReadedComplete = true;
			logger.error("导入数据出错!", e);
			throw new RuntimeException(e);
		}
		finally{
			//关掉对象,释放资料
			try{
				//判断是否读取多最后一行或异常  关闭文件流
				if (obj.isReadedComplete){
					if(br !=null){
						br.close();
						br = null;
					}
				}
			}catch(IOException e){
				logger.error("关闭文件流对象时异常!",e);
				throw new RuntimeException(e);
			}

		}
		return list;
	}


	/**
	 * 开发人员：【chenxuan】
	 * 创建/修改日期：【2019/5/17】
	 * 修改描述：加载文件
	 * @Param []
	 * @return void
	 **/
	public void loadTxt() throws  Exception{
		// 判断文件是否都存在,不存在则直接置为失败
		File file = new File(fileUrl);
		if (file == null || !file.exists() || !file.isFile()) {
			logger.info("找不到要导入的文件:" + fileUrl);
			throw  new RuntimeException("找不到要导入的文件:" + fileUrl);
		}
		// 检查文件大小,如果文件为零,则判断是否允许为空文件
		BigDecimal fileSize = new BigDecimal(file.length())
				.divide(BigDecimal.valueOf(1024.00 * 1024.00));
		logger.info("[文件大小(M)]:" + fileSize.toString());
		if (file.length() < 1) {
			throw  new RuntimeException("文件数据为空:" + fileUrl);
		}
		logger.info("开始装载...");
	}
	/**
	 * 开发人员：【chenxuan】
	 * 创建/修改日期：【2019/5/17】
	 * 修改描述：读取指定行数的记录并绑定到执行对象
	 * @Param [start, end, txtFileLoadBean]
	 * @return java.util.List<com.fdb.efp.nls.service.domain.TxtFileLoadBean>
	 **/
	public List<TxtFileLoadBean> fetchDataToObject(int start, int end,TxtFileLoadBean txtFileLoadBean) throws Exception {
		// 无法获取文本行数 ，无法指定List容量
		//  List<TxtFileLoadBean> list = new ArrayList<>(end-start+1);
		List<TxtFileLoadBean> list = new ArrayList<>();
		String s = null;
		try {
			//判断是否需要去除首行
			if(  start == 0 ) {
				//去除首行
				for(int i = 0;i<IsFirstline;i++){
					s = br.readLine();
				}
			}
			s = br.readLine();
			// 得到总条数和是否已读完的标志
			if (s == null) {
				txtFileLoadBean.setReadedComplete(true);
			}
			// 读取数据
			while (s != null) {
				// 有可能数据中有换行，所以读出来是空行，但接着又会有一行是数据
				if (!"".equals(s.trim())) {
					fileRecordCount++;
					if (fileRecordCount >= start) {
						TxtFileLoadBean tempLoanBean = txtFileLoadBean.clone();
						tempLoanBean =bindValueToObject(tempLoanBean,s);
						if (tempLoanBean != null) {
							list.add(tempLoanBean);
						}
						if (fileRecordCount == end)
							break;
					}
				}
				s = br.readLine();
			}
			return list;
		} catch (IOException e) {
			throw new Exception(e);
		}
	}


	/**
	 * 开发人员：【chenxuan】
	 * 创建/修改日期：【2019/5/17】
	 * 描述：绑定对象
	 * @Param [txtFileLoadBean, values]
	 * @return com.fdb.efp.nls.service.domain.TxtFileLoadBean
	 **/
	private TxtFileLoadBean bindValueToObject(TxtFileLoadBean txtFileLoadBean,String values) throws IllegalAccessException, InstantiationException {
		// 分解后得到一行包含的字段
		String[] frecord = values.split(dataSplit, -1);
		// 验证字段个数与数据个数是否匹配(最后一位必须带分隔符,所以减一)
		int dataLength = frecord.length;
		Field[] field = txtFileLoadBean.getClass().getDeclaredFields();
		if (dataLength < field.length) {

			logger.info("字段个数与数据个数不匹配" );
			throw new RuntimeException("字段个数与数据个数不匹配");
		}
		for (int i = 0; i < field.length; i++) {
			Field f = field[i];
			f.setAccessible(true);
			String type = f.getType().toString();
			if (type.endsWith("String")) {
				f.set(txtFileLoadBean, frecord[i]);
			}
			if (type.endsWith("int")) {
				if(StringUtil.isEmpty(frecord[i])) {
					f.set(txtFileLoadBean, 0);
				}else {
					f.set(txtFileLoadBean, Integer.parseInt(frecord[i]));
				}
			} if (type.endsWith("BigDecimal")) {
				if(StringUtil.isEmpty(frecord[i])) {
					f.set(txtFileLoadBean, null);
				}else {
					f.set(txtFileLoadBean, new BigDecimal(frecord[i]));
				}

			}
		}
		return txtFileLoadBean;
	}
	public void setFirstRead(boolean firstRead) {
		isFirstRead = firstRead;
	}

}
